---@class RedRob.ActorManager
local ActorManager = RedRob.CreateSingleton("ActorManager")
local this = ActorManager
function ActorManager.OnCreate()
    ---@type RedRob.Player[]
    this.actorList = {}     --场景视野/屏幕之内的玩家
    this.playerStaticId = 0
    ---@type RedRob.Player[]
    this.removeList = {}
    ---@type RedRob.Player[]
    this.waitingLoadList = {}
    ---@type RedRob.Player[]
    this.sortActorList = {}--排序用
    this.isSortDirty = false
    this.loadCountPer = 2   --单次加载数量
    ---@type RedRob.Pawn[]
    this.allActorList = {}    --玩家
    RedRob.ClientBattle.RegisterUpdateCallback(this.Update)
    RedRob.ClientBattle.RegisterLateUpdateCallback(this.LateUpdate)
end
function ActorManager.OnDestroy()
    if this.allActorList then
        for k,v in pairs(this.allActorList) do
            v:BaseDestroy()
        end
    end
    this.removeList = nil
    this.actorList = nil
    this.sortActorList = nil
    this.waitingLoadList = nil
    this.allActorList = nil
end
function ActorManager.GetUniqueId()
    this.playerStaticId = this.playerStaticId + 1
    return this.playerStaticId
end
---@return RedRob.Player
function ActorManager.CreatePlayer(pic)
    local player = RedRob.Player.New(RedRob.Config.ActorType.player)
    player:BaseCreate()
    player.clientId = this.GetUniqueId()
    player.skinId = pic
    local modelId = logicMgr.SkinManager.getHeroModelIdBySkinId(pic)
    player.modelId = modelId
    player.clientName = string.format(getLanguage("DarkLaneTipes_18"),player.clientId)--匿名
    player:SetHp(1000)
    player:SetHpMax(1000)
    player:SetPos(0,0)
    player:SetDir(true)
    player:EquipSkill()
    --local skill = player.skillMgr:GetSkill(RedRob.Config.SkillType.normalAttack)
    --skill:SetDamageValue(0)
    return player
end
function ActorManager.CreateMy(x,y)
    local mgr = logicMgr.HeroManager
    local data = PlayerObj.New()
    data.name = mgr.GetRoleName()
    data.playerId = mgr.GetRoleId()
    data.x = x
    data.y = y
    data.pic = mgr.GetRoleInfo("pic")
    data.unionName = ""
    data.direction = 1
    data.die = 0
    data.pkInfo = nil
    data.currMoney = 0
    data.attrReduce = 0
    data.buffList = {};
    data.picFrame = mgr.GetRoleHeadFrame()
    local player = this.CreateNetPlayer(data)
    RedRob.KeyController.SetCtrlId(data.playerId)
    RedRob.CameraController.SetFollowTarget(player)
end
---@return RedRob.Player
function ActorManager.CreateNetPlayer(data)
    local player = this.CreatePlayer(data.pic)
    RedRob.AiMgr.AddAi(player,RedRob.Config.AiType.playerAi)
    this.UpdateNetPlayer(player,data)
    FireEvent(RedRob.Config.Event.ActorCreate,player)
    return player
end
---@param data PlayerObj
---@param player RedRob.Player
function ActorManager.UpdateNetPlayer(player,data)
    player:SetPos(data.x,data.y)
    player.id = tostring(data.playerId)
    player.name = data.name
    player.unionName = data.unionName
    player.picFrame = data.picFrame
    player:SetDir(data.direction == 1)
    this.AddActor(player)
    if data.die == 1 then
        player:SetDead()
        player:StartReborn(dataTable.getGlobalInt(351)/1000)
    end
    for k,v in pairs(data.buffList) do
        player:AddBuff(v.buffId,v.overlay)
    end
    RedRob.GameMode.PlayerResourceUpdate(player:GetId(),data.currMoney)
    RedRob.GameMode.SetAttrReduce(player:GetId(),data.attrReduce)
    FireEvent(RedRob.Config.Event.PlayerResourceUpdate,player:GetId(),data.currMoney)
    FireEvent(RedRob.Config.Event.PlayerAttrReduce,player:GetId(),data.attrReduce)
end
---@param info PkInfo
function ActorManager.UpdateNetPkInfo(info)
    if not info then return end
    local id1 = tostring(info.playerId1)
    local id2 = tostring(info.playerId2)
    local player1 = RedRob.ActorManager.GetActor(id1)
    local player2 = RedRob.ActorManager.GetActor(id2)
    local p1Win = info.playerId1 == info.playerIdWin
    local p2Win = info.playerId2 == info.playerIdWin
    local start = tonumber(tostring(info.startTime/1000))
    if player1 then
        player1:LockHp(p1Win and info.remainHp/100 * player1:GetHpMax() or 0)
        player1:FightPlayer(player2,info.playerId1 == info.playerIdWin,start,info.time,info.x1,info.y1)
    else
        logError("no player1 "..tostring(info.playerId1))
    end
    if player2 then
        player2:LockHp(p2Win and info.remainHp/100 * player2:GetHpMax() or 0)
        player2:FightPlayer(player1,info.playerId2 == info.playerIdWin,start,info.time,info.x2,info.y2)
    else
        logError("no player2 "..tostring(info.playerId2))
    end
    local res1 = p1Win and info.moneyChange or -info.moneyChange
    local res2 = p2Win and info.moneyChange or -info.moneyChange
    local gm = RedRob.GameMode
    gm.PlayerResourceChange(id1,res1)
    gm.PlayerResourceChange(id2,res2)
    gm.SetWinStreakCount(id1,info.winStreak1)
    gm.SetWinStreakCount(id2,info.winStreak2)
    FireEvent(RedRob.Config.Event.PlayerResourceChange,id1,res1)
    FireEvent(RedRob.Config.Event.PlayerResourceChange,id2,res2)
end
---@param db MineralObj
function ActorManager.CreateNetMinerals(db)
    local a = RedRob.Minerals.New(RedRob.Config.ActorType.minerals)
    a:BaseCreate()
    a.id = tostring(db.objId)
    a.name = "box"..a.id
    a:SetModelId(db.modelId)
    a:SetPos(db.x,db.y)
    this.AddActor(a)
    FireEvent(RedRob.Config.Event.ActorCreate,a)
    return a
end
---@param db DarkStoneObj
function ActorManager.CreateNetStone(db)
    local a = RedRob.Stone.New(RedRob.Config.ActorType.stone)
    a:BaseCreate()
    a.id = tostring(db.objId)
    a.name = "box"..a.id
    a.hp = db.hp
    a.hpMax = db.maxHp
    a:SetModelId(db.modelId)
    a:SetPos(db.x,db.y)
    this.AddActor(a)
    FireEvent(RedRob.Config.Event.ActorCreate,a)
    return a
end
---@return RedRob.Player
function ActorManager.GetClickActor(hitTran)
    for k,v in pairs(this.actorList) do
        if v:GetTran() == hitTran then
            return v
        end
    end
    return nil
end

function ActorManager.GetPlayerCount()
    local count = 0
    for k,v in pairs(this.actorList) do
        if v.actorType == RedRob.Config.ActorType.player then
            count = count + 1
        end
    end
    return count
end
function ActorManager.ActorOutScene(id)
    local actor = this.allActorList[id]
    this.actorList[id] = nil
    if actor and actor:CanDestroyed() then
        this.DestroyActor(actor)
    end
end
---@param actor RedRob.Pawn
function ActorManager.ActorInScene(actor)
    if not actor then return end
    this.actorList[actor:GetId()] = actor
    actor:SetActive(true)
end

---@param actor RedRob.Player
function ActorManager.AddActor(actor)
    if actor == nil then return end
    local a = this.GetActor(actor:GetId())
    if a ~= nil then
       -- logError("尝试添加一个重复的actor:"..actor:GetId())
        return
    end
    this.actorList[actor:GetId()] = actor
    this.waitingLoadList[actor:GetId()] = actor
    this.allActorList[actor:GetId()] = actor
    RedRob.ReportMgr.Print("AddActor",actor:GetId(),actor:GetName())
end

---@param actor RedRob.Player
function ActorManager.DestroyActor(actor)
    if not actor then return end
    FireEvent(RedRob.Config.Event.ActorDestroy,actor)
    this.actorList[actor:GetId()] = nil
    this.allActorList[actor:GetId()] = nil
    actor:BaseDestroy()
    RedRob.ReportMgr.Print("DestroyActor",actor:GetId(),actor:GetName())
end

---@return RedRob.Player
function ActorManager.GetActor(playerId)
    if not this.actorList then return nil end
    local actor = this.actorList[playerId]
    return actor
end
---@return RedRob.Pawn
function ActorManager.GetActorInAll(playerId)
    if not this.actorList then return nil end
    local actor = this.allActorList[playerId]
    return actor
end
function ActorManager.GetActorList()
    return this.actorList
end
function ActorManager.NotifyActorPosChange()
    this.isSortDirty = true
end
function ActorManager.Update(dt)
    --checkDead
    table.clear(this.removeList)
    for k,v in pairs(this.actorList) do
        v:Update(dt)
    end
    --[[for k,v in pairs(this.removeList) do
        this.DestroyActor(v)
        this.waitingLoadList[v:GetId()] = nil
    end]]
    --table.clear(this.removeList)
    --loading
    local count = 0
    for k,v in pairs(this.waitingLoadList) do
        v:LoadModel()
        count = count + 1
        this.waitingLoadList[v:GetId()] = nil
        if count >= this.loadCountPer then
            break
        end
    end
end
function ActorManager.GetSortActorList()
    return this.sortActorList
end
function ActorManager.LateUpdate(dt)
    if this.isSortDirty then
        this.isSortDirty = false
        table.clear(this.sortActorList)
        for k,v in pairs(this.actorList) do
            table.insert(this.sortActorList,v)
        end
        table.sort(this.sortActorList,this.SortOrder)
        for k,v in pairs(this.sortActorList) do
            v:SetSortingOrder(k-1)
        end
    end

end
---@param a RedRob.Player
---@param b RedRob.Player
function ActorManager.SortOrder(a,b)
    local ay = a:GetPos().y
    local by = b:GetPos().y
    if ay ~= by then
        return ay > by
    end
    return a:GetId() < a:GetId()
end